/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { ArkAliasTypeDefineStmt, ArkFile, ArkMethod, ts } from "arkanalyzer";
import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger';
import { BaseChecker, BaseMetaData } from "../BaseChecker";
import { Defects, IssueReport } from "../../model/Defects";
import { Rule } from "../../model/Rule";
import { AstMatcher, MatcherCallback, MatcherTypes } from "../../matcher/Matchers";
import { RuleListUtil } from "../../utils/common/DefectsList";

const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'ForeachArgsCheck');
const gMetaData: BaseMetaData = {
    severity: 1,
    ruleDocPath: "docs/no-unnecessary-type-constraint.md",
    description: "Disallow unnecessary constraints on generic types"
};

const unnecessaryConstraint = ['any', 'unknown'];

export class NoUnnecessaryTypeConstraintCheck implements BaseChecker {
    readonly metaData: BaseMetaData = gMetaData;
    public rule: Rule;
    public defects: Defects[] = [];
    public issues: IssueReport[] = [];

    private astMatcher: AstMatcher = {
        matcherType: MatcherTypes.AST,
        match(node: ts.Node): boolean {
            return ts.isTypeParameterDeclaration(node);
        }
    };

    public registerMatchers(): MatcherCallback[] {
        const matchBuildCb: MatcherCallback = {
            matcher: this.astMatcher,
            callback: this.check
        }
        return [matchBuildCb];
    }

    public check = (node: ts.TypeParameterDeclaration, file: ArkFile): void => {
        if (file.getName().endsWith('.ets')) {
            return;
        }
        const constraintNode = node.constraint;
        if (constraintNode) {
            const typeConstraint = constraintNode.getText();
            if (!unnecessaryConstraint.includes(typeConstraint)) {
                return;
            }
            let pos = file.getAST()?.getLineAndCharacterOfPosition(node.getStart());
            if (!pos) {
                return;
            }
            const severity = this.rule.alert ?? this.metaData.severity;
            const genericParam = node.name.getText();
            const description = `Constraining the generic type \`${genericParam}\` to \`${typeConstraint}\` does nothing and is unnecessary.`;
            const line = pos.line + 1;
            const column = pos.character + 1;
            const columnEnd = file.getAST()?.getLineAndCharacterOfPosition(node.getEnd()).character;
            let defect = new Defects(line, column, columnEnd ? columnEnd + 1 : column, description, severity,
                this.rule.ruleId, file.getFilePath(), this.metaData.ruleDocPath, true, false, false);
            this.issues.push(new IssueReport(defect, undefined));
            RuleListUtil.push(defect);
        }
    };

}